package com.central.apps.controller;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.central.app.service.HandlerService;
import com.central.apps.dto.*;
import com.central.apps.entity.Document;
import com.central.apps.service.OnlineEditService;
import com.central.apps.util.FileUtil;
import com.central.apps.util.Md5Utils;
import com.central.common.auth.details.LoginAppUser;
import com.central.common.util.SysUserUtil;
import com.central.common.web.Result;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.hashids.Hashids;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author JHY
 */
@Slf4j
@Api(tags = "OnlyOffice在线编辑接口")
@CrossOrigin
@Controller
@RequestMapping("/onlyOffice")
public class OnlyOfficeController {
    @Resource
    private FileUtil fileUtil;
    @Resource
    private OnlineEditService onlineEditService;

    @Value("${files.docservice.url.callbackUrl}")
    private String callbackUrl;
    @Value("${files.docservice.url.site}")
    private String officeUrl;
    @Value("${files.docservice.url.command}")
    private String officeCommand;
    @Autowired
    private HandlerService handlerService;

    /**
     * 下载文档接口
     *
     * @param response
     */
    @GetMapping("/download")
    public void download(String fileid, String appname, HttpServletResponse response) {
        System.out.println(" ==========>  enter download <========== ");
//        List<Map<String, Object>> fileList =
//                handlerService.findBySql("select * from tb_file where appname = '" + appname + "' AND isshow=1 AND recordid =" +
//                        fileid + " ORDER BY `uploadtime` DESC");
//        String filepath = MapUtil.getStr(fileList.get(0), "filepath");
        Map<String, String> fileData = onlineEditService.getFilePath(fileid, appname);
        String pathname = MapUtil.getStr(fileData, "pathname"); // /home/eam/doclinks/综合管理部
        String filename = MapUtil.getStr(fileData, "filename");// 2022-11-01_170621_9a7e421b-54e6-441a-9d84-e9941209d217.docx
        try {
            FileUtil.downLoadFile(pathname, filename, response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @GetMapping("/edit")
    public String editDocFile(@RequestParam String fileid, String appname, String access_token, String status, Model model) {
        System.out.println(" ==========>  enter editDocFile <========== ");
        //获取当前登陆人
        LoginAppUser user = SysUserUtil.getLoginAppUser();
        // 用户ID
        Long id = user.getId();
        // 用户账号
        String username = user.getUsername();

        Map<String, String> fileData = onlineEditService.getFilePath(fileid, appname);
        String filepath = MapUtil.getStr(fileData, "filepath");
        String filerealname = MapUtil.getStr(fileData, "filerealname");
        String downloadurl = MapUtil.getStr(fileData, "downloadurl");
        String fileUserName = MapUtil.getStr(fileData, "fileUserName");
        String extensionname = MapUtil.getStr(fileData, "extensionname");
        String md5 = MapUtil.getStr(fileData, "md5");
        System.out.println(" ==========> 结束文件DB查询 <========== ");
        System.out.println(" ==========> editDocFile fileData:" + fileData);
        String fileType = StringUtils.lowerCase(FilenameUtils.getExtension(filepath));
        System.out.println(" ==========> fileType:" + fileType);
        String url = callbackUrl + "api-apps/onlyOffice/download?fileid=" + fileid + "&appname=" + appname + "&access_token=" + access_token;
        String cburl = callbackUrl + "api-apps/onlyOffice/callback?fileid=" + fileid + "&appname=" + appname + "&access_token=" + access_token;
        System.out.println(" ==========> url:" + url);
        System.out.println(" ==========> cburl:" + cburl);
        String key = Md5Utils.md5(LocalDateTime.now().toString());
        Document document = new Document();
        document.setKey(key);
        document.setTitle(filerealname);
        document.setFileType(fileType);
        document.setStorage(downloadurl);
        document.setUrl(url);
        document.setToken(access_token);
        document.setType("desktop");
        document.setWidth("100%");
        document.setHeight("100%");
        document.setDocumentType(getDocumentType(extensionname));

        // 编辑器配置
        EditorConfigDTO editorConfig = new EditorConfigDTO();
        editorConfig.setLang("zh-CN");
        editorConfig.setMode("edit");
        editorConfig.setCallbackUrl(cburl);
        editorConfig.setUser(new EditorConfigUserDTO(id.toString(), username));
        editorConfig.setRecent(new ArrayList<>());
        editorConfig.setCustomization(
                new EditorConfigCustomDTO(false, false, false, false,
                        false,
                        new EditorConfigCustomerDTO("地址信息", "额外信息",
                                "http://60.205.187.187:9000/douyin/logo_1680505766874.png",
                                "http://60.205.187.187:9000/douyin/logo_1680505766874.png",
                                "邮箱@163.com", "GQOFFICE", "152xxxxxxxx", "http://219.239.83.21:56655/"),
                        new EditorConfigFeedbackDTO(false),
                        true, false, false, false, false, 100, false
                )
        );
        document.setEditorConfig(editorConfig);
        // 设置插件列表
        EditorConfigPluginsDTO editorConfigPluginsDTO = new EditorConfigPluginsDTO();
        editorConfigPluginsDTO.setAutostart(new ArrayList<>());
        editorConfigPluginsDTO.setPluginsData(new ArrayList<>());
        editorConfig.setPlugins(editorConfigPluginsDTO);

        PermissionDTO permissionDTO = new PermissionDTO();
        permissionDTO.setChangeHistory(false);
        permissionDTO.setChat(false);
        permissionDTO.setComment(false);
        /**
         * TODO 手动模拟文档赋权
         */
        if (fileUserName.equals(username)) {
            permissionDTO.setCopy(true);
            permissionDTO.setDeleteCommentAuthorOnly(true);
            permissionDTO.setDownload(true);
            permissionDTO.setEdit(true);
            permissionDTO.setEditCommentAuthorOnly(true);
            permissionDTO.setFillForms(true);
            permissionDTO.setModifyContentControl(true);
            permissionDTO.setModifyFilter(true);
            permissionDTO.setPrint(true);
            permissionDTO.setProtect(true);
            permissionDTO.setRename(true);
            permissionDTO.setReview(true);
        } else {
            // FillForms 填充表单
            permissionDTO.setCopy(true);
            permissionDTO.setDeleteCommentAuthorOnly(true);
            permissionDTO.setDownload(true);
            permissionDTO.setEdit(false);
            permissionDTO.setEditCommentAuthorOnly(true);
            permissionDTO.setFillForms(true);
            permissionDTO.setModifyContentControl(true);
            permissionDTO.setModifyFilter(true);
            permissionDTO.setPrint(true);
            permissionDTO.setProtect(true);
            permissionDTO.setRename(true);
            permissionDTO.setReview(false);
        }
        if (StringUtils.isNotBlank(status)) {
            if (!"新建".equals(status)) {
                permissionDTO.setCopy(true);
                permissionDTO.setDeleteCommentAuthorOnly(true);
                permissionDTO.setDownload(true);
                // 禁止编辑
                permissionDTO.setEdit(false);
                permissionDTO.setEditCommentAuthorOnly(true);
                permissionDTO.setFillForms(true);
                permissionDTO.setModifyContentControl(true);
                permissionDTO.setModifyFilter(true);
                permissionDTO.setPrint(true);
                permissionDTO.setProtect(true);
                permissionDTO.setRename(true);
                permissionDTO.setReview(false);
            }
        }
        // 设置文档权限
        document.setPermissions(permissionDTO);

        System.out.println(" ==========> 文档配置信息 :" + JSON.toJSONString(document));

        model.addAttribute("document", document);
        return "editor";
    }


    /**
     * 编辑文档时回调接口
     * <p>
     * 1 - 正在编辑文档，
     * 每次用户连接到文档或断开文档共同编辑时都会收到它。使用它们的回调 URL。
     * 请注意，当用户返回到文档时，也可以收到状态 1，并且在 Internet 问题后没有更改。这种情况可以描述如下：
     * 当用户打开文档时，将发送状态 1。
     * 如果 Internet 连接丢失，并且用户未对文档进行任何更改，则发送状态 4。 屏幕上会显示错误，并在查看器中打开文档。
     * 在 100 秒内，互联网连接将恢复，用户将重新连接到文档，并再次发送状态 1。
     * 现在，用户可以继续编辑文档。将收到状态 2 或 4，具体取决于用户是否对文档进行了任何更改。
     * 2 - 文档已准备好保存，
     * 3 - 发生文档保存错误，
     * (2,3)在关闭文档进行编辑 10 秒后，将使用最后一个将更改发送到文档编辑服务的用户的标识符接收到该文档。 使用上次对文件进行更改的用户的回调 URL。
     * 4 - 文档已关闭，没有更改，
     * 在关闭文档进行编辑后，最后一个用户不会对其进行任何更改，将收到它。使用它们的回调 URL。
     * 6 - 正在编辑文档，但当前文档状态已保存，
     * 7 - 强制保存文档时出错。
     * (6,7)在执行强制节省请求时收到它。
     * 回调网址取决于forceavetype参数：
     * 如果 forceavetype 参数设置为 1，则使用单击“保存”按钮的用户的回调 URL。
     * 如果 forceavetype 参数设置为 0 或 2，则使用上次对文件进行更改的用户的回调 URL。
     * 从版本 5.5 到版本 6.1，始终使用上次对文件进行更改的用户的回调 URL。
     */
    @RequestMapping("/callback")
    public void saveDocumentFile(HttpServletRequest request, HttpServletResponse response) {
        System.out.println(" ==========>  enter callback <========== ");
        String fileid = request.getParameter("fileid");
        String appname = request.getParameter("appname");
        System.out.println(" ==========> 文件ID :" + fileid + " ,appname :" + appname);
        Map<String, String> fileData = onlineEditService.getFilePath(fileid, appname);
        String downloadurl = MapUtil.getStr(fileData, "downloadurl");
        System.out.println(" ==========> 结束文件DB查询 <========== ");
        System.out.println(" ==========> saveDocumentFile fileData:" + fileData);
        PrintWriter writer = null;
        JSONObject jsonObj = null;
        try {
            writer = response.getWriter();
            Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
            String body = scanner.hasNext() ? scanner.next() : "";
            jsonObj = (JSONObject) new JSONParser().parse(body);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (Objects.isNull(jsonObj)) {
            System.out.println("jsonObj is null");
            if (Objects.nonNull(writer)) {
                writer.write("{\"error\":0}");
            }
            return;
        }
        Object statusObj = jsonObj.get("status");
        if (Objects.isNull(statusObj)) {
            System.out.println("statusObj is null");
            if (Objects.nonNull(writer)) {
                writer.write("{\"error\":0}");
            }
            return;
        }
        int status = Integer.parseInt(statusObj.toString());
        System.out.println("jsonObj:" + JSON.toJSONString(jsonObj));
        System.out.println(" ===> 保存状态 :" + status);
        String downloadUri = (String) jsonObj.get("url");
        System.out.println("downloadUri:" + downloadUri);
        if (status == 1) {
            System.out.println("保存状态, status=1," + status);
            if (writer != null) {
                writer.write("{\"error\":0}");
            }
            return;
        } else if (status == 2) {
            System.out.println("保存状态, status=2," + status);
            InputStream inputStream = null;
            OutputStream out = null;
            try {
                URL url = new URL(downloadUri);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(1000 * 60 * 5);
                // 检查状态码
                int statusCode = connection.getResponseCode();
                System.out.println("文档下载状态码：" + statusCode);
                if (statusCode == HttpURLConnection.HTTP_OK) {
                    inputStream = connection.getInputStream();
                    File savedFile = new File(downloadurl);
                    String key = FileUtil.getFileMd5(savedFile);
                    System.out.println("文件MD5:" + key);
                    System.out.println("文件路径:" + downloadurl);
                    // 定义输出文件
                    out = new FileOutputStream(savedFile);
                    // 读取InputStream中的数据并写入文件
                    int read;
                    byte[] bytes = new byte[1024];
                    while ((read = inputStream.read(bytes)) != -1) {
                        out.write(bytes, 0, read);
                    }
                    System.out.println("文件已成功写入本地！");
                    onlineEditService.updateByFileId(key, fileid);
                    System.out.println("修改tb_file成功");
                } else {
                    System.out.println("下载失败，状态码为：" + statusCode);
                }

            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("status=2:" + e.getMessage());
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null) {
                    try {
                        out.flush();
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }

        } else if (status == 6 || status == 7) {
            System.out.println("保存状态, status=6||7," + status);
            InputStream inputStream = null;
            OutputStream out = null;
            try {
                URL url = new URL(downloadUri);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(1000 * 60 * 5);
                // 检查状态码
                int statusCode = connection.getResponseCode();
                System.out.println("文档下载状态码：" + statusCode);
                if (statusCode == HttpURLConnection.HTTP_OK) {
                    inputStream = connection.getInputStream();
                    File savedFile = new File(downloadurl);
                    String key = FileUtil.getFileMd5(savedFile);
                    System.out.println("文件MD5:" + key);
                    System.out.println("文件路径:" + downloadurl);
                    // 定义输出文件
                    out = new FileOutputStream(savedFile);
                    // 读取InputStream中的数据并写入文件
                    int read;
                    byte[] bytes = new byte[1024];
                    while ((read = inputStream.read(bytes)) != -1) {
                        out.write(bytes, 0, read);
                    }
                    System.out.println("文件已成功写入本地！");
                    onlineEditService.updateByFileId(key, fileid);
                    System.out.println("修改tb_file成功");
                } else {
                    System.out.println("下载失败，状态码为：" + statusCode);
                }

            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("status=2:" + e.getMessage());
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null) {
                    try {
                        out.flush();
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        } else {
            System.out.println("未知保存状态, status=" + status);
            if (writer != null) {
                writer.write("{\"error\":0}");
            }
        }
        writer.write("{\"error\":0}");
    }

    /**
     * @return
     */
    @GetMapping("/editStatus")
    public ResponseEntity<Object> getDoucmentEditStatus(String name) throws ParseException {
        System.out.println(" ==========>  enter editStatus <========== ");
        String url = officeUrl + officeCommand;
        Map<String, String> map = new HashMap<String, String>();
        map.put("c", "forcesave");
        /*
        String docFileMd5 = Md5Utils.getFileMd5(new File(filePath + name));
        if (StringUtils.isBlank(docFileMd5)) {
            throw new RuntimeException("目标文档md5校验失败");
        }
        String pathShortMd5 = Md5Utils.md5(filePath + name);
        String nameShortMd5 = Md5Utils.md5(name);
        Hashids hashids = new Hashids("lezhixing");
        // (将路径字符串短md5值 + 名称字符串短md5值) ==> 再转成短id形式 ==> 作为文档的key（暂且认为是不会重复的）
        String key = hashids.encodeHex(String.format("%s%s%s", docFileMd5, pathShortMd5, nameShortMd5));
        map.put("key", key);
        */

        map.put("userdata", "sample userdata");
        JSONObject obj = (JSONObject) new JSONParser().parse(FileUtil.editStatus(url, JSON.toJSONString(map)));
        System.out.println(" ==========>  obj : " + JSON.toJSONString(obj));
        System.out.println(" ==========>  end editStatus <========== ");
        return new ResponseEntity<Object>(obj, HttpStatus.OK);
    }

    public String getDocumentType(String type) {
        switch (type) {
            case "doc":
            case "docx":
                return "word";
            case "xls":
            case "xlsx":
                return "cell";
            case "pps":
            case "ppt":
            case "pptx":
                return "slide";
            default:
                return "word";
        }
    }


}
